#pragma once
/*
    日志器模块对前面模块进行整合,完成不同等级的日志输出
*/

#include "Util.hpp"
#include "LogFormat.hpp"
#include "LogLevel.hpp"
#include "LogSink.hpp"
#include "Looper.hpp"
#include <atomic>
#include <mutex>
#include <cstdarg>
#include <unordered_map>

namespace log
{
    class Logger
    {
    public:
        using ptr = std::shared_ptr<Logger>;
        Logger(const std::string &logger_name, Formatter::ptr &formatter,
               std::vector<LogTo::ptr> &sinks,
               LogLevel::level level) : _logger_name(logger_name), _Formatter(formatter), _sinks(sinks.begin(), sinks.end()), _limit_level(level)
        {
        }
        // 1:构建日志并2:得到格式化字符串,3:提供不同等级的日志输出
        const std::string &name() { return _logger_name; }
        void Debug(const std::string &file, size_t line, const char *fmt, ...)
        {
            // 1.先判断是否要输出
            if (LogLevel::level::DEBUG < _limit_level)
            {
                return;
            }

            // 2将格式化字符串fmt中内容提取出来
            va_list ap;
            va_start(ap, fmt);
            char *buf;
            int ret = vasprintf(&buf, fmt, ap);
            if (ret == -1)
            {
                std::cout << "vasprintf failed\n";
            }
            serialize(LogLevel::level::DEBUG, file, line, buf);
            free(buf);
        }
        void Info(const std::string &file, size_t line, const char *fmt, ...)
        {
            if (LogLevel::level::INFO < _limit_level)
            {
                return;
            }

            // 2将格式化字符串fmt中内容提取出来
            va_list ap;
            va_start(ap, fmt);
            char *buf;
            int ret = vasprintf(&buf, fmt, ap);
            if (ret == -1)
            {
                std::cout << "vasprintf failed\n";
            }
            serialize(LogLevel::level::INFO, file, line, buf);
            free(buf);
        }
        void Warn(const std::string &file, size_t line, const char *fmt, ...)
        {
            if (LogLevel::level::WARNING < _limit_level)
            {
                return;
            }
            // 2将格式化字符串fmt中内容提取出来
            va_list ap;
            va_start(ap, fmt);
            char *buf;
            int ret = vasprintf(&buf, fmt, ap);
            if (ret == -1)
            {
                std::cout << "vasprintf failed\n";
                return;
            }
            va_end(ap);
            serialize(LogLevel::level::WARNING, file, line, buf);
            free(buf);
        }
        void Error(const std::string &file, size_t line, const char *fmt, ...)
        {
            if (LogLevel::level::ERROR < _limit_level)
            {
                return;
            }
            // 2将格式化字符串fmt中内容提取出来
            va_list ap;
            va_start(ap, fmt);
            char *buf;
            int ret = vasprintf(&buf, fmt, ap);
            if (ret == -1)
            {
                std::cout << "vasprintf failed\n";
                return;
            }
            va_end(ap);
            serialize(LogLevel::level::ERROR, file, line, buf);
            free(buf);
        }
        void Fatal(const std::string &file, size_t line, const char *fmt, ...)
        {
            if (LogLevel::level::FATAL < _limit_level)
            {
                return;
            }
            // 2将格式化字符串fmt中内容提取出来
            va_list ap;
            va_start(ap, fmt);
            char *buf;
            int ret = vasprintf(&buf, fmt, ap);
            if (ret == -1)
            {
                std::cout << "vasprintf failed\n";
                return;
            }
            va_end(ap);
            serialize(LogLevel::level::FATAL, file, line, buf);
            free(buf);
        }

    private:
        // 抽象出来的意义是因为不同的日志器可能落地方式不一样  直接向磁盘/标准输出 或者先向一段内存中先写入
        virtual void log(const char *data, size_t size) = 0;
        void serialize(LogLevel::level level, const std::string file, size_t line, char *buf)
        {
            // 3:构建日志对象
            LogMessage Msg(level, file, line, _logger_name, buf);
            // 4:将日志进行格式化,得到字符串
            std::stringstream ss;
            _Formatter->Format(ss, Msg); // 格式化后的字符存在ss中
            // 日志落地
            log(ss.str().c_str(), ss.str().size());
        }

    protected:
        std::string _logger_name;
        Formatter::ptr _Formatter;      // 格式化器,完成格式化
        std::vector<LogTo::ptr> _sinks; // 落地方向的数组,日志器可以向不同方向进行写入
        std::mutex _mtx;
        // 因为要大量的访问该成员,在多线程并发的场景保证线程安全
        std::atomic<LogLevel::level> _limit_level; // 限制等级,小于该等级的日志不会被输出
    };
    // 同步日志器将日志通过日志句柄直接进行日志落地
    class SyncLogger : public Logger
    {
    public:
        using ptr = std::shared_ptr<SyncLogger>;
        SyncLogger(const std::string &logger_name, Formatter::ptr &formatter, std::vector<LogTo::ptr> &sinks, LogLevel::level level)
            : Logger(logger_name, formatter, sinks, level)
        {
        }

    private:
        void log(const char *data, size_t size) override
        {
            // 加锁保证多线程日志写入的时候不会出现问题
            std::unique_lock<std::mutex> lock(_mtx); // 自动加锁与释放锁
            if (_sinks.empty())
                return;
            for (auto &e : _sinks)
            {
                e->WriteLog(data, size);
            }
        }
    };

    class AsynLogger : public Logger
    {
    public:
        AsynLogger(const std::string &logger_name, Formatter::ptr &formatter,
                   std::vector<LogTo::ptr> &sinks, LogLevel::level level,
                   LooperType loopertype)
            : Logger(logger_name, formatter, sinks, level), _looper(std::make_shared<AsyncLooper>(
                                                                std::bind(&AsynLogger::reallog, this, std::placeholders::_1), loopertype)) {}
        void log(const char *data, size_t size) override
        {
            _looper->Push(data, size);
        }
        void reallog(Buffer &buf)
        {
            if (_sinks.empty())
                return;
            for (auto &e : _sinks)
            {
                e->WriteLog(buf.Begin(), buf.ReadAbleSize());
            }
        }

    private:
        AsyncLooper::ptr _looper;
    };

    enum class LoggerType
    {
        LOGGER_SYNC,
        LOGGER_ASYNC
    };
    // 日志器建造者类,用户在创建日志器的时候很麻烦,我们提供一个建造者类让用户简单创造日志器
    // 抽象一个日志建造者基类,因为后面还有全局日志器与局部日志器
    class LoggerBuilder // 这个日志器建造者类 完成日志器各个零部件的构造,具体创建日志器在具体的子类中派生出来
    {
    public:
        using ptr = std::shared_ptr<LoggerBuilder>;
        LoggerBuilder() : _LoggerType(LoggerType::LOGGER_SYNC),
                          _limit_level(LogLevel::level::DEBUG),
                          _loopertype(LooperType::SAFE)

        {
        }

    public:
        void BuildLoggerName(const std::string &name) { _logger_name = name; }
        template <typename SinkType, typename... Args>
        void BuildLoggerSinks(Args &&...args)
        {
            LogTo::ptr sptr = SinkFactory::CreateSink<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(sptr);
        }
        void BuildLoggerFormatter(const std::string &pattern)
        {
            _Formatter = std::make_shared<Formatter>(pattern);
        }
        void BuildLoggerLevel(LogLevel::level level) { _limit_level = level; }
        void BuildLoggerType(LoggerType loggertype) { _LoggerType = loggertype; }
        void BuildAsynceUnsafeType() { _loopertype = LooperType::UNSAFE; }
        // 日志器的构建
        virtual Logger::ptr build() = 0;

    protected:
        LooperType _loopertype;
        LoggerType _LoggerType;
        std::string _logger_name;
        Formatter::ptr _Formatter;      // 格式化器,完成格式化
        std::vector<LogTo::ptr> _sinks; //
        LogLevel::level _limit_level;   // 限制等级,小于该等级的日志不会被输出
    };
    // 局部日志器
    class LocalLoggerBuilder : public LoggerBuilder
    {
    public:
        using ptr = std::shared_ptr<LocalLoggerBuilder>;
        Logger::ptr build() override
        {
            // 一定要有名称,作为日志器的唯一标识
            assert(!_logger_name.empty());
            // 如果用户未给日志的格式
            if (_Formatter.get() == nullptr)
            {
                _Formatter = std::make_shared<Formatter>();
            }
            // 如果没有落地方向默认向标准输出中打印
            if (_sinks.empty())
            {
                BuildLoggerSinks<LogToStdout>();
            }

            if (_LoggerType == LoggerType::LOGGER_ASYNC)
            {
                // 异步日志器的创建
                return std::make_shared<AsynLogger>(_logger_name, _Formatter, _sinks, _limit_level, _loopertype);
            }
            // 同步日志器
            return std::make_shared<SyncLogger>(_logger_name, _Formatter, _sinks, _limit_level);
        }

    private:
    };

    class LoggerManager
    {
    public:
        static LoggerManager &GetInstance()
        {
            // c++11之后对于静态局部变量的定义过程是原子的,线程安全的
            static LoggerManager LM;
            return LM;
        }
    
        Logger::ptr GetRootLogger()
        {
            std::unique_lock<std::mutex> lock(_mtx);
            return _root_logger;
        }
        bool HasLogger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mtx);

            auto iter = _loggers.find(name);
            if (iter == _loggers.end())
                return false;
            return true;
        }
        void AddLogger(Logger::ptr &logger)
        {
            std::unique_lock<std::mutex> lock(_mtx);

            _loggers.insert(std::make_pair(logger->name(), logger));
        }
        Logger::ptr GetLogger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mtx);

            auto iter = _loggers.find(name);
            if (iter == _loggers.end())
                return Logger::ptr();
            return iter->second;
        }

    private:
        LoggerManager()
        {
            LoggerBuilder::ptr builder = std::make_shared<LocalLoggerBuilder>();
            builder->BuildLoggerName("root");
            _root_logger = builder->build();
            _loggers.insert(std::make_pair("root", _root_logger));
        }

    private:
        Logger::ptr _root_logger;                                   // 默认的日志器
        std::unordered_map<std::string, log::Logger::ptr> _loggers; // 使用unordered_map更方便对日志器进行查找
        std::mutex _mtx;
    };
    class GlobalLoggerBuilder : public LoggerBuilder
    {
    public:
        using ptr = std::shared_ptr<GlobalLoggerBuilder>;
        Logger::ptr build() override
        {
            // 一定要有名称,作为日志器的唯一标识
            assert(!_logger_name.empty());
            // 如果用户未给日志的格式
            if (_Formatter.get() == nullptr)
            {
                _Formatter = std::make_shared<Formatter>();
            }
            // 如果没有落地方向默认向标准输出中打印
            if (_sinks.empty())
            {
                BuildLoggerSinks<LogToStdout>();
            }
            Logger::ptr logger;
            if (_LoggerType == LoggerType::LOGGER_ASYNC)
            {
                // 异步日志器的创建
                logger = std::make_shared<AsynLogger>(_logger_name, _Formatter, _sinks, _limit_level, _loopertype);
            }
            // 同步日志器
            else
                logger = std::make_shared<SyncLogger>(_logger_name, _Formatter, _sinks, _limit_level);
            LoggerManager::GetInstance().AddLogger(logger);
            // std::cout<<logger->name()<<std::endl;

            return logger;
        }

    private:
    };

}
